#include "ClassicSimulationInput.h"

#include <Windowsx.h>

ClassicSimulationInput* ClassicSimulationInput::m_instance(nullptr);

ClassicSimulationInput::ClassicSimulationInput( HWND windowHandle ) : m_windowHandle(windowHandle),
	m_mouseMovement(DirectX::XMINT2(0, 0))
{
	if(m_instance)
	{
		MessageBox( nullptr,
			L"ClassicSimulationInput may not be constructed multiple times",
			L"Error",
			MB_OK );
		exit(EXIT_FAILURE);
	}
	m_instance = this;
	GetClientRect( m_windowHandle, &m_windowRect );
	m_windowWidth = m_windowRect.right - m_windowRect.left;
	m_windowHeight = m_windowRect.bottom - m_windowRect.top;
	m_relativeWindowMiddle = DirectX::XMINT2(m_windowWidth / 2, m_windowHeight / 2);
	ZeroMemory(&m_inputGiven[0], INPUTKEY_MAX * sizeof(int));
}

ClassicSimulationInput::~ClassicSimulationInput(void)
{
}

LRESULT CALLBACK ClassicSimulationInput::WndProc( HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam )
{
	if (windowHandle == GetFocus())
	{
		PAINTSTRUCT paintStruct;
		HDC hdc;
		switch( message )
		{
		case WM_PAINT:
			hdc = BeginPaint( windowHandle, &paintStruct );
			EndPaint( windowHandle, &paintStruct );
			return 0;
		case WM_DESTROY:
			PostQuitMessage( 0 );
			return 0;

		case WM_CHAR:
			switch (wParam)
			{
			case VK_ESCAPE:
				PostQuitMessage( 0 );
				return 0;
			case 'p': case 'P':
				m_instance->m_inputGiven[KeySnapshot] += 1;
				break;
			case VK_RETURN:
				m_instance->m_inputGiven[KeySnapshot] += 1;
				break;
			case '1':
				m_instance->m_inputGiven[GoToFreeMode] = 1;
				break;
			case '2':
				m_instance->m_inputGiven[GoToViewMode] = 1;
				break;
			case 'b': case 'B':
				m_instance->m_inputGiven[KeySwitchUseBumpMap] = 1;
				break;
			case 'n': case 'N':
				m_instance->m_inputGiven[KeyBumpiness] -= 1;
				break;
			case 'm': case 'M':
				m_instance->m_inputGiven[KeyBumpiness] += 1;
				break;
			case 'v': case 'V':
				m_instance->m_inputGiven[KeySwitchRasterizer] = 1;
				break;
			case 'r': case 'R':
				m_instance->m_inputGiven[KeySendRay] = 1;
				break;
			case 'k': case 'K':
				m_instance->m_inputGiven[KeyToggleShowKdTree] = 1;
				break;
			case 'l': case 'L':
				m_instance->m_inputGiven[KeyStepAntiAliasingMode] = 1;
				break;
			case 'o': case 'O':
				m_instance->m_inputGiven[KeyToggleAntiAliasing] = 1;
			}
			break;

		case WM_KEYDOWN:
			switch (wParam)
			{
			case VK_UP: case 'w': case 'W':
				m_instance->m_inputGiven[Forward] = 1;
				break;
			case VK_DOWN: case 's': case 'S':
				m_instance->m_inputGiven[Backward] = 1;
				break;
			case VK_RIGHT: case 'd': case 'D':
				m_instance->m_inputGiven[Right] = 1;
				break;
			case VK_LEFT: case 'a': case 'A':
				m_instance->m_inputGiven[Left] = 1;
				break;
			case VK_CONTROL:
				m_instance->m_inputGiven[Downward] = 1;
				break;
			case VK_SPACE:
				m_instance->m_inputGiven[Upward] = 1;
				break;
			case VK_DELETE: case VK_BACK:
				m_instance->m_inputGiven[KeyClearSnapshots] = 1;
				break;
			}
			break;

		case WM_KEYUP:
			switch (wParam)
			{
			case VK_UP: case 'w': case 'W':
				m_instance->m_inputGiven[Forward] = 0;
				break;
			case VK_DOWN: case 's': case 'S':
				m_instance->m_inputGiven[Backward] = 0;
				break;
			case VK_RIGHT: case 'd': case 'D':
				m_instance->m_inputGiven[Right] = 0;
				break;
			case VK_LEFT: case 'a': case 'A':
				m_instance->m_inputGiven[Left] = 0;
				break;
			case VK_CONTROL:
				m_instance->m_inputGiven[Downward] = 0;
				break;
			case VK_SPACE:
				m_instance->m_inputGiven[Upward] = 0;
				break;
			}
			break;

		case WM_MOUSEMOVE:
			{
				DirectX::XMINT2 middle = m_instance->m_relativeWindowMiddle;
				m_instance->m_mouseMovement = DirectX::XMINT2(GET_X_LPARAM(lParam) - middle.x, GET_Y_LPARAM(lParam) - middle.y);
			}
			break;
		default:
			return DefWindowProc( windowHandle, message, wParam, lParam );
		} 
	}
	else
	{
		return DefWindowProc( windowHandle, message, wParam, lParam );
	}
}

void ClassicSimulationInput::Reset( void )
{
	m_mouseMovement = DirectX::XMINT2(0, 0);
}

DirectX::XMINT2 ClassicSimulationInput::GetMouseMovement( void )
{
	if(m_windowHandle == GetActiveWindow())
	{
		static LPPOINT screenWindowMiddle = new POINT;
		screenWindowMiddle->x = m_relativeWindowMiddle.x;
		screenWindowMiddle->y = m_relativeWindowMiddle.y;
		ClientToScreen(m_windowHandle, screenWindowMiddle);
		SetCursorPos(screenWindowMiddle->x, screenWindowMiddle->y);
	}
	DirectX::XMINT2 result = m_mouseMovement;
	Reset();
	return result;
}

float ClassicSimulationInput::GetHorizontalMovement( void )
{
	return static_cast<float>(m_inputGiven[Right] - m_inputGiven[Left]);
}

float ClassicSimulationInput::GetForwardMovement( void )
{
	return static_cast<float>(m_inputGiven[Forward] - m_inputGiven[Backward]);
}

float ClassicSimulationInput::GetVerticalMovement( void )
{
	return static_cast<float>(m_inputGiven[Upward] - m_inputGiven[Downward]);
}

int ClassicSimulationInput::GetBumpinessManipulator( void )
{
	int returnValue = m_inputGiven[KeyBumpiness];
	m_inputGiven[KeyBumpiness] = 0;
	return returnValue;
}

int ClassicSimulationInput::GetNumSnapshotCommands( void )
{
	int returnValue = m_inputGiven[KeySnapshot];
	m_inputGiven[KeySnapshot] = 0;
	return returnValue;
}

bool ClassicSimulationInput::GetShouldGoToFreeMode( void )
{
	bool returnvalue = m_inputGiven[GoToFreeMode] == 1;
	m_inputGiven[GoToFreeMode] = m_inputGiven[GoToViewMode] = 0;
	return returnvalue;
}

bool ClassicSimulationInput::GetShouldGoToViewMode( void )
{
	bool returnvalue = m_inputGiven[GoToViewMode] == 1;
	m_inputGiven[GoToFreeMode] = m_inputGiven[GoToViewMode] = 0;
	return returnvalue;
}

bool ClassicSimulationInput::GetShouldClearSnapshots( void )
{
	bool returnvalue = m_inputGiven[KeyClearSnapshots] == 1;
	m_inputGiven[KeyClearSnapshots] = 0;
	return returnvalue;
}

bool ClassicSimulationInput::GetShouldSwitchUseBumpMap( void )
{
	bool returnvalue = m_inputGiven[KeySwitchUseBumpMap] == 1;
	m_inputGiven[KeySwitchUseBumpMap] = 0;
	return returnvalue;
}

bool ClassicSimulationInput::GetShouldSwitchRasterizer( void )
{
	bool returnvalue = m_inputGiven[KeySwitchRasterizer] == 1;
	m_inputGiven[KeySwitchRasterizer] = 0;
	return returnvalue;
}

bool ClassicSimulationInput::GetShouldSendRay( void )
{
	bool returnvalue = m_inputGiven[KeySendRay] == 1;
	m_inputGiven[KeySendRay] = 0;
	return returnvalue;
}

bool ClassicSimulationInput::GetShouldToggleShowKdTree( void )
{
	bool returnvalue = m_inputGiven[KeyToggleShowKdTree] == 1;
	m_inputGiven[KeyToggleShowKdTree] = 0;
	return returnvalue;
}

bool ClassicSimulationInput::GetShouldStepAntiAliasingMode( void )
{
	bool returnvalue = m_inputGiven[KeyStepAntiAliasingMode] == 1;
	m_inputGiven[KeyStepAntiAliasingMode] = 0;
	return returnvalue;
}

bool ClassicSimulationInput::GetShouldToggleAntiAliasing( void )
{
	bool returnvalue = m_inputGiven[KeyToggleAntiAliasing] == 1;
	m_inputGiven[KeyToggleAntiAliasing] = 0;
	return returnvalue;
}
